// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LIB_FPROMISE_SINGLE_THREADED_EXECUTOR_H_
#define LIB_FPROMISE_SINGLE_THREADED_EXECUTOR_H_

#include <utility>

#include "promise.h"
#include "scheduler.h"

namespace fpromise {

// A simple platform-independent single-threaded asynchronous task executor.
//
// This implementation is designed for use when writing simple single-threaded
// platform-independent applications.  It may be less efficient or provide
// fewer features than more specialized or platform-dependent executors.
//
// See documentation of |fpromise::promise| for more information.
class single_threaded_executor final : public executor {
 public:
  single_threaded_executor();

  // Destroys the executor along with all of its remaining scheduled tasks
  // that have yet to complete.
  ~single_threaded_executor() override;

  // Schedules a task for eventual execution by the executor.
  //
  // This method is thread-safe.
  void schedule_task(pending_task task) override;

  // Runs all scheduled tasks (including additional tasks scheduled while
  // they run) until none remain.
  //
  // This method is thread-safe but must only be called on at most one
  // thread at a time.
  void run();

  single_threaded_executor(const single_threaded_executor&) = delete;
  single_threaded_executor(single_threaded_executor&&) = delete;
  single_threaded_executor& operator=(const single_threaded_executor&) = delete;
  single_threaded_executor& operator=(single_threaded_executor&&) = delete;

 private:
  class dispatcher_impl;

  // The task context for tasks run by the executor.
  class context_impl final : public context {
   public:
    explicit context_impl(single_threaded_executor* executor);
    ~context_impl() override;

    single_threaded_executor* executor() const override;
    suspended_task suspend_task() override;

   private:
    single_threaded_executor* const executor_;
  };

  context_impl context_;
  dispatcher_impl* const dispatcher_;
};

// Creates a new |fpromise::single_threaded_executor|, schedules a promise as a task,
// runs all of the executor's scheduled tasks until none remain, then returns
// the promise's result.
template <typename Continuation>
static typename promise_impl<Continuation>::result_type run_single_threaded(
    promise_impl<Continuation> promise) {
  using result_type = typename promise_impl<Continuation>::result_type;
  single_threaded_executor exec;
  result_type saved_result;
  exec.schedule_task(
      promise.then([&saved_result](result_type& result) { saved_result = std::move(result); }));
  exec.run();
  return saved_result;
}

}  // namespace fpromise

#endif  // LIB_FPROMISE_SINGLE_THREADED_EXECUTOR_H_
